/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.utils;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.*;
import cn.easyplatform.messages.request.*;
import cn.easyplatform.messages.request.vfs.ReadRequestMessage;
import cn.easyplatform.messages.vos.*;
import cn.easyplatform.messages.vos.datalist.ListGetValueVo;
import cn.easyplatform.messages.vos.datalist.ListHeaderVo;
import cn.easyplatform.messages.vos.datalist.ListSetValueVo;
import cn.easyplatform.messages.vos.h5.MsnVo;
import cn.easyplatform.messages.vos.h5.PushFieldVo;
import cn.easyplatform.messages.vos.h5.PushVo;
import cn.easyplatform.spi.service.*;
import cn.easyplatform.type.*;
import cn.easyplatform.web.WebApps;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.layout.IMainTaskBuilder;
import cn.easyplatform.web.layout.LayoutManagerFactory;
import cn.easyplatform.web.log.LogManager;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.EventSupport;
import cn.easyplatform.web.task.MainTaskSupport;
import cn.easyplatform.web.task.zkex.ListSupport;
import cn.easyplatform.web.task.zkex.list.PanelSupport;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.*;
import org.zkoss.util.Locales;
import org.zkoss.util.resource.Labels;
import org.zkoss.web.servlet.Servlets;
import org.zkoss.web.servlet.http.Https;
import org.zkoss.zk.ui.*;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.http.ExecutionImpl;
import org.zkoss.zk.ui.http.I18Ns;
import org.zkoss.zk.ui.http.WebManager;
import org.zkoss.zk.ui.impl.RequestInfoImpl;
import org.zkoss.zk.ui.metainfo.PageDefinition;
import org.zkoss.zk.ui.sys.RequestInfo;
import org.zkoss.zk.ui.sys.SessionCtrl;
import org.zkoss.zk.ui.sys.UiFactory;
import org.zkoss.zk.ui.sys.WebAppCtrl;
import org.zkoss.zul.*;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cn.easyplatform.messages.vos.h5.MessageVo.TYPE_TASK;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public final class WebUtils {

    /**
     * @param size
     * @return
     */
    public final static int px0(String size) {
        size = StringUtils.substringBefore(size, "px");
        return Nums.toInt(size, 0);
    }

    /**
     * 判断是否是列表中组件触发的事件
     *
     * @return
     */
    public final static boolean isCellEvent() {
        Event evt = Contexts.getEvent();
        if (evt == null || evt.getTarget().getParent() == null)
            return false;
        Component parent = evt.getTarget().getParent();
        int deep = 0;
        while (deep < 6) {
            if (parent instanceof Listcell || parent instanceof Treecell || parent instanceof Row) {
                return true;
            } else {
                parent = parent.getParent();
                if (parent == null || parent instanceof Window)
                    break;
            }
            deep++;
        }
        return false;
    }

    /**
     * 根据row类型设置列表选择记录
     *
     * @param anchor
     */
    public final static void setAnchor(Component anchor) {
        if (anchor instanceof Listitem) {
            ((Listitem) anchor).getListbox().setSelectedIndex(-1);
            ((Listitem) anchor).setSelected(true);
        } else if (anchor instanceof Treeitem) {
            ((Treeitem) anchor).getTree().setSelectedItem(null);
            ((Treeitem) anchor).setSelected(true);
        } else
            ((Row) anchor).getGrid().setAttribute("selectRow", anchor);
    }

    /**
     * 列表记录对应的数据
     *
     * @param anchor
     * @return
     */
    public final static ListRowVo getAnchorValue(Component anchor) {
        ListRowVo vo;
        if (anchor instanceof Listitem)
            vo = ((Listitem) anchor).getValue();
        else if (anchor instanceof Treeitem)
            vo = ((Treeitem) anchor).getValue();
        else
            vo = ((Row) anchor).getValue();
        if (vo == null)
            throw new UiException(Labels.getLabel("datalist.item.value"));
        return vo;
    }

    /**
     * 获取所在行受管组件
     *
     * @param ls
     * @param row
     * @return
     */
    public final static Map<String, Component> getManagedComponents(ListSupport ls, Component row) {
        Map<String, Component> managedComponents = new HashMap<String, Component>();
        int size = ls.getHeaders().size();
        for (int i = 0; i < size; i++) {
            ListHeaderVo hv = ls.getHeaders().get(i);
            if (hv.isVisible()) {
                Component c = null;
                if (row instanceof Treeitem)
                    c = row.getFirstChild().getChildren().get(i);
                else
                    c = row.getChildren().get(i);
                if (c.getFirstChild() != null) {
                    if (c.getFirstChild() instanceof Idspace) {
                        for (Component comp : c.getFirstChild().getFellows())
                            managedComponents.put(comp.getId(), comp);
                        continue;
                    } else
                        c = c.getFirstChild();
                }
                managedComponents.put(hv.getName(), c);
            }
        }
        return managedComponents;
    }

    /**
     * 获取所在行受管组件
     *
     * @param ls
     * @param row
     * @return
     */
    public final static ListRowVo getItemData(ListSupport ls, Component row) {
        ListRowVo rv = null;
        if (row instanceof Treeitem)
            rv = ((Treeitem) row).getValue();
        else if (row instanceof Listitem)
            rv = ((Listitem) row).getValue();
        else
            rv = ((Row) row).getValue();
        List<Component> children = null;
        if (row instanceof Treeitem)
            children = row.getFirstChild().getChildren();
        else
            children = row.getChildren();
        int size = ls.getHeaders().size();
        for (Component c : children) {
            if (c.getFirstChild() != null) {
                if (c.getFirstChild() instanceof Idspace) {
                    for (Component comp : c.getFirstChild().getFellows()) {
                        String name = (String) comp.getAttribute("$f0");
                        if (name != null) {
                            for (int i = 0; i < size; i++) {
                                ListHeaderVo hv = ls.getHeaders().get(i);
                                if (name.equals(hv.getField()) && hv.isEditable()) {
                                    if (ls.getEntity().isShowRowNumbers())
                                        rv.getData()[i - 1] = PageUtils.getValue(comp, true);
                                    else
                                        rv.getData()[i] = PageUtils.getValue(comp, true);
                                    break;
                                }
                            }
                        }
                    }
                } else {
                    String name = (String) c.getFirstChild().getAttribute("$f0");
                    if (name != null) {
                        for (int i = 0; i < size; i++) {
                            ListHeaderVo hv = ls.getHeaders().get(i);
                            if (name.equals(hv.getField()) && hv.isEditable()) {
                                if (ls.getEntity().isShowRowNumbers())
                                    rv.getData()[i - 1] = PageUtils.getValue(c.getFirstChild(), true);
                                else
                                    rv.getData()[i] = PageUtils.getValue(c.getFirstChild(), true);
                                break;
                            }
                        }
                    }
                }
            } else {
                String name = (String) c.getAttribute("$f0");
                if (name != null) {
                    for (int i = 0; i < size; i++) {
                        ListHeaderVo hv = ls.getHeaders().get(i);
                        if (name.equals(hv.getField()) && hv.isEditable()) {
                            if (ls.getEntity().isShowRowNumbers())
                                rv.getData()[i - 1] = PageUtils.getValue(c, true);
                            else
                                rv.getData()[i] = PageUtils.getValue(c, true);
                            break;
                        }
                    }
                }
            }
        }
        return rv;
    }

    /**
     * 格式化指定的对象
     *
     * @param fmt
     * @param v
     * @return
     */
    public static String format(String fmt, Object v) {
        if (v instanceof Date) {
            Date date = (Date) v;
            if (fmt.equals("medium+short")) {
                return DateFormat.getDateInstance(DateFormat.LONG).format(date) + " " + new SimpleDateFormat("HH:mm:ss").format(date);
            } else if (fmt.equals("medium")) {
                return DateFormat.getDateInstance(DateFormat.MEDIUM).format(date);
            } else if (fmt.equals("long")) {
                return new SimpleDateFormat("HH:mm:ss").format(date);
            } else {
                SimpleDateFormat sdf = new SimpleDateFormat(fmt);
                return sdf.format(date);
            }
        } else if (v instanceof Number) {
            if (fmt.contains("MM") || fmt.contains("mm")) {
                SimpleDateFormat sdf = new SimpleDateFormat(fmt);
                return sdf.format(((Number) v).longValue());
            }
            DecimalFormat df = new DecimalFormat(fmt);
            return df.format(v);
        }
        return v.toString();
    }

    /**
     * @param field
     * @return
     */
    public static String format(FieldVo field) {
        String format = getFormat(field);
        if (!Strings.isBlank(format))
            return format(format, field.getValue());
        return field.getValue().toString();
    }

    /**
     * @param fv
     * @return
     */
    public final static String getFormat(FieldVo fv) {
        if (fv.getType() == FieldType.DATETIME)
            return "medium+short";
        else if (fv.getType() == FieldType.DATE)
            return "medium";
        else if (fv.getType() == FieldType.TIME)
            return "long";
        else if (fv.getDecimal() >= 0)
            return getFormat(fv.getDecimal());
        else
            return null;
    }

    /**
     * 通过币别来设置小数位
     *
     * @param acc
     * @return
     */
    public final static String getFormat(String id, String acc) {
        int decimal = Nums.toInt(acc, -1);
        if (decimal >= 0 && decimal < 10)
            return getFormat(decimal);
        else {// 币别
            ApplicationService ac = ServiceLocator.lookup(ApplicationService.class);
            IResponseMessage<?> resp = ac.getAcc(new GetAccRequestMessage(id, new AccVo(acc)));
            if (resp.isSuccess()) {
                if (resp.getBody() != null) {
                    decimal = (Integer) resp.getBody();
                    return getFormat(decimal);
                } else {
                    try {
                        decimal = Currency.getInstance(acc.toUpperCase()).getDefaultFractionDigits();
                        return getFormat(decimal);
                    } catch (Exception e) {
                        return getFormat(Currency.getInstance(Locales.getCurrent()).getDefaultFractionDigits());
                    }
                }

            } else {
                try {
                    decimal = Currency.getInstance(acc.toUpperCase()).getDefaultFractionDigits();
                    return getFormat(decimal);
                } catch (Exception e) {
                    return getFormat(Currency.getInstance(Locales.getCurrent()).getDefaultFractionDigits());
                }
            }
        }
    }

    /**
     * @param decimal
     * @return
     */
    public final static String getFormat(int decimal) {
        if (decimal == 0)
            return "###,##0";
        StringBuilder sb = new StringBuilder("###,##0.");
        for (int i = 0; i < decimal; i++)
            sb.append("0");
        return sb.toString();
    }

    public final static String getFormat(ListSupport support, ListHeaderVo header, ListRowVo rv) {
        String format = header.getFormat();
        if (format == null) {
            return null;
        } else if (format.startsWith("$")) {
            String acc = format.substring(1);
            boolean find = false;
            for (int i = 0; i < support.getHeaders().size(); i++) {
                ListHeaderVo hv = support.getHeaders().get(i);
                if (hv.getField() != null && hv.getField().equalsIgnoreCase(acc)) {
                    if (support.getEntity().isShowRowNumbers())
                        acc = rv.getData()[i - 1] == null ? Currency.getInstance(Locales.getCurrent()).getDisplayName() : rv.getData()[i - 1].toString();
                    else
                        acc = rv.getData()[i] == null ? Currency.getInstance(Locales.getCurrent()).getDisplayName() : rv.getData()[i].toString();
                    find = true;
                    break;
                }
            }
            // 找后端数据
            if (find) {
                if (header.getType() == FieldType.NUMERIC) {
                    ApplicationService ac = ServiceLocator.lookup(ApplicationService.class);
                    IResponseMessage<?> resp = ac.getAcc(new GetAccRequestMessage(support.getComponent().getId(), new AccVo(acc)));
                    if (resp.isSuccess()) {
                        if (resp.getBody() != null) {
                            int decimal = (Integer) resp.getBody();
                            return getFormat(decimal);
                        } else {
                            try {
                                int decimal = Currency.getInstance(acc.toUpperCase()).getDefaultFractionDigits();
                                return getFormat(decimal);
                            } catch (Exception e) {
                                return getFormat(Currency.getInstance(Locales.getCurrent()).getDefaultFractionDigits());
                            }
                        }
                    } else {
                        try {
                            int decimal = Currency.getInstance(acc.toUpperCase()).getDefaultFractionDigits();
                            return getFormat(decimal);
                        } catch (Exception e) {
                            return getFormat(Currency.getInstance(Locales.getCurrent()).getDefaultFractionDigits());
                        }
                    }
                } else
                    return acc;
            } else if (header.getType() == FieldType.NUMERIC) {
                return getFormat(Currency.getInstance(Locales.getCurrent()).getDefaultFractionDigits());
            } else
                return acc;
        }
        return format;
    }

    /**
     * @param ctx
     * @param pp
     * @param tt
     * @return
     */
    public static String getUrl(String ctx, String pp, String tt) {
        StringBuilder sb = new StringBuilder();
        sb.append(ctx);
        if (!pp.equals(""))
            sb.append("/").append(pp);
        sb.append(tt);
        return sb.toString();
    }

    /**
     * 检查是否有功能已执行
     *
     * @param task
     * @return
     */
    public final static int checkTask(Object task, Component container) {
        Map<String, Object> repo = Contexts.getDesktop().getAttributes();
        for (Object o : repo.values()) {
            if (o instanceof TaskInfo) {
                TaskInfo ti = (TaskInfo) o;
                if (ti.equals(task) || ti.getTaskId().equals(task)) {
                    if (container instanceof Tabbox) {
                        Tabbox tb = (Tabbox) container;
                        for (Component tab : tb.getTabs().getChildren()) {
                            if (tab.getId().equals(ti.getId())) {
                                ((Tab) tab).setSelected(true);
                                return 0;
                            }
                        }
                    }
                    return 1;
                }
            }
        }
        return -1;
    }

    /**
     * 注册新功能
     *
     * @param task
     */
    public final static void registryTask(TaskInfo task) {
        if (!Strings.isBlank(task.getParentId())) {// EMBBED
            Map<String, Object> repo = Contexts.getDesktop().getAttributes();
            TaskInfo parent = (TaskInfo) repo.get(task.getParentId());
            if (parent != null) {
                if (parent.getChildren() != null) {
                    Iterator<TaskInfo> itr = parent.getChildren().iterator();
                    while (itr.hasNext()) {
                        if (task.getTaskId().equals(itr.next().getTaskId())) {
                            itr.remove();
                            break;
                        }
                    }
                }
                parent.addChild(task);
            }
        } else
            Contexts.getDesktop().set(task.getId(), task);
    }

    /**
     * 删除功能
     *
     * @param id
     */
    public final static void removeTask(String id) {
        Contexts.getDesktop().remove(id);
    }

    /**
     * @param id
     */
    public static void removeChildren(String id) {
        Map<String, Object> repo = Contexts.getDesktop().getAttributes();
        for (Object o : repo.values()) {
            if (o instanceof TaskInfo) {
                TaskInfo ti = (TaskInfo) o;
                if (ti.getId().equals(id)) {
                    if (ti.getChildren() != null)
                        ti.getChildren().clear();
                    return;
                }
            }
        }
    }

    /**
     * 设置匿名页面信息
     *
     * @param desktop
     * @param id
     */
    public final static void setAnonymousInfo(Desktop desktop, String id) {
        List<String> ids = (List<String>) desktop.getAttribute(Contexts.ANONYMOUS_TASKS);//保存当前页面功能id
        if (ids != null) {
            ids.add(id);
            List<String> sessIds = (List<String>) desktop.getSession().getAttribute(Contexts.ANONYMOUS_TASKS);//保存当前会话所有功能id
            if (sessIds == null)
                desktop.getSession().setAttribute(Contexts.ANONYMOUS_TASKS, sessIds = new ArrayList<>());
            sessIds.add(id);
        }
    }

    /**
     * 创建项目目录
     *
     * @param env
     */
    public final static void createAppPath(EnvVo env) {
        File file = new File(new StringBuilder(WebApps.getRealPath()).append(File.separatorChar).append("apps").append(File.separatorChar).append(env.getProjectId()).toString());
        if (!file.exists())
            Files.createDirIfNoExists(file);
        file = new File(WebApps.me().getWorkspace() + "/" + env.getProjectId());
        if (!file.exists())
            Files.createDirIfNoExists(file);
    }

    /**
     * 读取#include的脚本内容
     *
     * @param name
     * @return
     */
    public final static String getScriptContent(String name) {
        if (name.endsWith(".js")) {
            StringBuilder sb = new StringBuilder(100);
            sb.append(WebApps.getRealPath()).append(File.separatorChar).append("WEB-INF").append(File.separatorChar).append("jstools").append(File.separatorChar).append(name);
            try {
                return Streams.readAndClose(new FileReader(sb.toString()));
            } catch (IOException e) {
                throw Lang.wrapThrow(e);
            }
        } else {
            AddonService as = ServiceLocator
                    .lookup(AddonService.class);
            IResponseMessage<?> resp = as
                    .getEntity(new SimpleTextRequestMessage(name));
            if (resp.isSuccess()) {
                return (String) resp.getBody();
            } else
                return "";
        }
    }

    /**
     * 获取后端栏位值
     *
     * @param handler
     * @param name
     * @return
     */
    public final static Object getFieldValue(EventSupport handler, String name) {
        if ("724".equals(name))
            return Contexts.getEnv().getDeviceType();
        if (handler instanceof MainTaskSupport) {
            if ("814".equals(name))
                return ((MainTaskSupport) handler).getProcessCode();
            else if ("801".equals(name))
                return ((MainTaskSupport) handler).getTaskId();
            else if ("802".equals(name))
                return ((MainTaskSupport) handler).getName();
            IResponseMessage<?> resp = ServiceLocator.lookup(
                    TaskService.class).getValue(
                    new GetValueRequestMessage(handler.getId(), new GetValueVo(name)));
            if (!resp.isSuccess())
                throw new BackendException(resp);
            return resp.getBody();
        } else if (handler instanceof ListSupport
                || handler instanceof PanelSupport) {
            Object[] data = null;
            ListSupport dls = null;
            if (handler instanceof ListSupport) {
                dls = (ListSupport) handler;
                if ("814".equals(name))
                    return dls.getMainHandler().getProcessCode();
                else if ("801".equals(name))
                    return dls.getMainHandler().getTaskId();
                else if ("802".equals(name))
                    return dls.getMainHandler().getName();
                ListRowVo row = dls.getSelectedValue();
                if (row != null)
                    data = dls.isCustom() ? row.getData() : row.getKeys();
            } else {
                dls = ((PanelSupport) handler).getList();
                if ("814".equals(name))
                    return dls.getMainHandler().getProcessCode();
                else if ("801".equals(name))
                    return dls.getMainHandler().getTaskId();
                else if ("802".equals(name))
                    return dls.getMainHandler().getName();
            }
            String listId = dls.getComponent().getId();

            IResponseMessage<?> resp = ServiceLocator.lookup(
                    TaskService.class).getValue(
                    new GetValueRequestMessage(handler.getId(), new ListGetValueVo(name,
                            listId, data)));
            if (!resp.isSuccess())
                throw new BackendException(resp);
            return resp.getBody();
        }
        return null;
    }

    /**
     * 给后端栏位赋值
     *
     * @param handler
     * @param name
     */
    public final static void setFieldValue(EventSupport handler, String name, Object value) {
        if (handler instanceof MainTaskSupport) {
            IResponseMessage<?> resp = ServiceLocator.lookup(
                    TaskService.class).setValue(
                    new SetValueRequestMessage(handler.getId(), new SetValueVo(
                            name, value)));
            if (!resp.isSuccess())
                throw new BackendException(resp);
        } else if (handler instanceof ListSupport
                || handler instanceof PanelSupport) {
            Object[] data = null;
            ListSupport dls = null;
            if (handler instanceof ListSupport) {
                dls = (ListSupport) handler;
                ListRowVo row = dls.getSelectedValue();
                if (row != null)
                    data = dls.isCustom() ? row.getData() : row.getKeys();
            } else
                dls = ((PanelSupport) handler).getList();
            String listId = dls.getComponent().getId();
            IResponseMessage<?> resp = ServiceLocator.lookup(
                    TaskService.class).setValue(
                    new SetValueRequestMessage(handler.getId(),
                            new ListSetValueVo(name, value, listId, data)));
            if (!resp.isSuccess())
                throw new BackendException(resp);
        }
    }

    /**
     * @param fn
     * @return
     */
    public final static String getFile(String fn) {
        return getFile(fn, Contexts.getEnv(), Contexts.getUser().getId());
    }

    /**
     * @param path
     * @return
     */
    private final static String getFile(String path, EnvVo env, String userId) {
        if (path.startsWith("$707") || path.startsWith("$729"))
            throw new EasyPlatformWithLabelKeyException("File is not allowed here.");
        //本地文件
        if (path.startsWith("$708")) {
            path = path.replace("$708", WebApps.me().getWorkspace() + File.separatorChar + env.getProjectId());
        } else if (path.startsWith("$730")) {
            path = path.replace("$730", WebApps.me().getWorkspace() + File.separatorChar + env.getProjectId() + File.separatorChar + userId);
        } else if (path.startsWith("$7")) {
            throw new EasyPlatformWithLabelKeyException("File is not allowed here.");
        } else {
            if (path.startsWith("/"))
                path = WebApps.getRealPath(path);
            else
                path = WebApps.getRealPath("apps" + File.separatorChar + env.getProjectId() + File.separatorChar + path);
        }
        return FilenameUtils.normalize(path);
    }

    /**
     * zk内部调用
     *
     * @param fn
     * @return
     */
    public final static byte[] getFileContent(String fn) {
        return getFileContent(Contexts.getEnv(), Contexts.getUser().getId(), fn);
    }

    /**
     * 获取文件内容
     * 通过servlet调用
     *
     * @param env
     * @param userId
     * @param fn
     * @return
     */
    public final static byte[] getFileContent(EnvVo env, String userId, String fn) {
        //服务器上的文件
        if (fn.startsWith("$707") || fn.startsWith("$729")) {
            ReadRequestMessage req = new ReadRequestMessage(fn);
            req.setSessionId(env.getSessionId());
            IResponseMessage<?> resp = ServiceLocator.lookup(VfsService.class).read(req);
            if (!resp.isSuccess())
                throw new BackendException(resp);
            return (byte[]) resp.getBody();
        }
        fn = getFile(fn, env, userId);
        InputStream is = null;
        try {
            is = new FileInputStream(fn);
            return IOUtils.toByteArray(is);
        } catch (FileNotFoundException e) {
            throw new EasyPlatformWithLabelKeyException("common.error",
                    FilenameUtils.getName(fn) + " not found.");
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    /**
     * 处理页面
     *
     * @param request
     * @param response
     * @param xul
     * @throws IOException
     */
    public final static void processZul(HttpServletRequest request,
                                        HttpServletResponse response, String xul) throws IOException {
        ServletContext ctx = request.getServletContext();
        final WebManager webman = WebManager.getWebManager(ctx);
        final WebApp wapp = webman.getWebApp();
        final WebAppCtrl wappc = (WebAppCtrl) wapp;
        final Session sess = WebManager.getSession(ctx, request);
        final Object old = I18Ns.setup(sess, request, response, "UTF-8");
        StringWriter out = null;
        OutputStream os = null;
        String result = null;
        try {
            final String path = Https.getThisServletPath(request);
            final Desktop desktop = webman.getDesktop(sess, request, response,
                    path, true);
            if (desktop == null)
                return;

            final RequestInfo ri = new RequestInfoImpl(wapp, sess, desktop,
                    request, null);
            ((SessionCtrl) sess).notifyClientRequest(true);
            final UiFactory uf = wappc.getUiFactory();
            PageDefinition pagedef = uf.getPageDefinitionDirectly(ri, xul,
                    "zul");
            final Page page = WebManager.newPage(uf, ri, pagedef, response,
                    path);
            final Execution exec = new ExecutionImpl(ctx, request, response,
                    desktop, page);
            out = new StringWriter(4096 * 2);
            wappc.getUiEngine().execNewPage(exec, pagedef, page, out);
            String cs = response.getCharacterEncoding();
            if (cs == null || cs.length() == 0)
                cs = "UTF-8";
            result = out.toString();
            os = response.getOutputStream();
            byte[] data = result.getBytes(cs);
            if (!Servlets.isIncluded(request) && data.length > 200) {
                byte[] bs = Https.gzip(request, response, null, data);
                if (bs != null)
                    data = bs;
            }
            response.setContentLength(data.length);
            os.write(data);
            os.flush();
        } catch (IllegalStateException ex) {
            if (result != null)
                response.getWriter().write(result);
            else
                throw ex;
        } catch (UiException ex) {
            throw ex;
        } finally {
            Streams.safeClose(out);
            Streams.safeClose(os);
            I18Ns.cleanup(request, old);
        }
    }

    /**
     * 预览zul页面
     *
     * @param content
     * @param target
     */
    public final static void preview(String content, Component target) {
        Pattern pattern = Pattern.compile("<\\?(script|style)(.*)\\?>", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(content);
        List<Element> elms = new ArrayList<>();
        while (matcher.find()) {
            String[] strArray = matcher.group(2).split(" ");
            for (String val : strArray) {
                if (val.startsWith("href")) {
                    Element elm = DocumentHelper.createElement(matcher.group(1));
                    elm.addAttribute("src", StringUtils.substringBetween(StringUtils.substringAfter(val, "="), "\"", "\""));
                    elms.add(elm);
                    break;
                }
            }
        }
        try {
            Document doc = DocumentHelper.parseText(content);
            Node node = doc.selectSingleNode("//@apply");
            if (node != null)//删除apply属性
                node.getParent().remove(node);
            Element e = doc.getRootElement().element("script");//移除运行脚本
            if (e != null)
                e.detach();
            String xul;
            if (!elms.isEmpty()) {
                Element root = DocumentHelper.createElement("zk");
                for (Element element : elms)
                    root.add(element);
                root.add(doc.getRootElement());
                xul = root.asXML();
            } else
                xul = doc.getRootElement().asXML();
            Window win = new Window(Labels.getLabel("explorer.preview"), "normal", true);
            win.setMaximizable(true);
            win.setSizable(true);
            win.setWidth("70%");
            win.setHeight("70%");
            win.setPage(target.getPage());
            Executions.getCurrent().createComponentsDirectly(xul, "zul", win, null);
            win.doHighlighted();
        } catch (DocumentException e) {
            throw new WrongValueException(target, Labels.getLabel("common.page.fomat", new String[]{e.getMessage()}));
        }
    }

    /**
     * 处理待办事项
     *
     * @param container
     * @param id
     */
    public static void doBpm(Component container, Object id) {
        ApiService ms = ServiceLocator.lookup(ApiService.class);
        MsnVo mv = new MsnVo();
        mv.setMsgid(Nums.toLong(id, 0));
        mv.setType(TYPE_TASK);
        IResponseMessage<?> resp = ms.poll(new SimpleRequestMessage(mv));
        if (resp.isSuccess()) {
            PushVo pv = (PushVo) resp.getBody();
            TaskInfo taskInfo = new TaskInfo(pv.getId());
            if (pv.getFields() != null) {
                Object[] keys = new Object[pv.getFields().size()];
                for (int i = 0; i < keys.length; i++)
                    keys[i] = pv.getFields().get(i).getValue();
                taskInfo.setKeys(keys);
            }
            int c = WebUtils.checkTask(taskInfo, container);
            if (c == 1 || c == 0) {
                if (c == 1)
                    MessageBox.showMessage(Labels
                            .getLabel("message.dialog.title.error"), Labels
                            .getLabel("main.task.has.run",
                                    new String[]{pv.getId()}));
                return;
            }
            TaskVo tv = new TaskVo(pv.getId());
            if (container.getPage().getFirstRoot() == container)
                tv.setOpenModel(Constants.OPEN_MODAL);
            else
                tv.setOpenModel(pv.getOpenModel());
            tv.setProcessCode(pv.getCode());
            List<FieldVo> vars = new ArrayList<FieldVo>();
            FieldVo field = new FieldVo(FieldType.LONG);
            field.setName("sys_msgid");
            field.setValue(mv.getMsgid());
            vars.add(field);
            if (pv.getFields() != null && !pv.getFields().isEmpty()) {
                for (PushFieldVo pf : pv.getFields()) {
                    field = new FieldVo(FieldType.cast(pf.getValue()));
                    field.setName(pf.getName());
                    field.setValue(pf.getValue());
                    vars.add(field);
                }
            }
            tv.setVariables(vars);
            AuthorizationVo av = Contexts.getUserAuthorzation();
            String roleId = null;
            if (av.getRoles().isEmpty())
                roleId = "default";
            else
                roleId = av.getRoles().get(0).getId();
            tv.setRoleId(roleId);
            TaskService mtc = ServiceLocator
                    .lookup(TaskService.class);
            BeginRequestMessage req = new BeginRequestMessage(tv);
            resp = mtc.begin(req);
            if (resp.isSuccess()) {
                if (resp.getBody() != null
                        && resp.getBody() instanceof AbstractPageVo) {
                    AbstractPageVo page = (AbstractPageVo) resp.getBody();
                    taskInfo.setId(page.getId());
                    taskInfo.setTitle(page.getTitile());
                    taskInfo.setImage(page.getImage());
                    WebUtils.registryTask(taskInfo);
                    MainTaskSupport builder = null;
                    try {
                        LogManager.beginRequest();
                        builder = (MainTaskSupport) LayoutManagerFactory
                                .createLayoutManager()
                                .getMainTaskBuilder(container,
                                        tv.getId(), page);
                        ((IMainTaskBuilder) builder).build();
                    } catch (EasyPlatformWithLabelKeyException ex) {
                        builder.close(false);
                        MessageBox.showMessage(ex);
                    } catch (BackendException ex) {
                        builder.close(false);
                        MessageBox.showMessage(ex.getMsg().getCode(), (String) ex
                                .getMsg().getBody());
                    } catch (Exception ex) {
                        builder.close(false);
                        MessageBox.showMessage(
                                Labels.getLabel("message.dialog.title.error"),
                                ex.getMessage());
                    } finally {
                        LogManager.endRequest();
                    }
                }
            } else
                MessageBox.showMessage(resp);
        } else
            MessageBox.showMessage(resp);
    }

}
